/*

 */ 
#include "epoll.h"
#include <sys/epoll.h>
#include <memory>
#include <unordered_map>
#include <vector>
#include "log.h"
#include "util.h"
#include "channel.h"
#include "httpData.h"


const int EVENTSNUM = 4096;
const int EPOLLWAIT_TIME = 10000;

using namespace std;
Epoll::Epoll():m_epollfd(epoll_create1(EPOLL_CLOEXEC)),m_events(EVENTSNUM){}

Epoll::~Epoll(){}
void Epoll::add_timer(ptr_channel chan,int timeout)
{
    shared_ptr<HttpData> t = chan->getHolder();  //weak_ptr观察的Http对象
    if(t)
        m_tq.add_timer(t,timeout);
    else
        record()<< "timer add fail";
}
void Epoll::epoll_add(ptr_channel chan, int timeout)
{
    int fd = chan->getFd();
    if(timeout > 0)
    {
        add_timer(chan,timeout);
        m_https[fd] = chan->getHolder();
    }
    struct epoll_event event;
    event.data.fd = fd;
    event.events = chan->getEvents();
    chan->EqualAndUpdateLastEvents();
    m_channels[fd] = chan;   //save channel
    if(epoll_ctl(m_epollfd,EPOLL_CTL_ADD, fd, &event) < 0)
    {
        record()<< getpid() <<": epoll_add error" ;
        m_channels[fd].reset();
    }
}
void Epoll::epoll_mod(ptr_channel chan, int timeout)
{
    if (timeout > 0) add_timer(chan, timeout);
    int fd = chan->getFd();
    if(!chan->EqualAndUpdateLastEvents()) {
        struct epoll_event event;
        event.data.fd = fd;
        event.events = chan->getEvents();
        if (epoll_ctl(m_epollfd, EPOLL_CTL_MOD, fd, &event) < 0) {
            record()<< getpid() <<": epoll_mod error" ;
            m_channels[fd].reset();
        }
    }
}
void Epoll::epoll_del(ptr_channel chan)
{
    int fd = chan->getFd();
    struct epoll_event event;
    event.data.fd = fd;
    event.events = chan->getLastEvents();
    if(epoll_ctl(m_epollfd,EPOLL_CTL_DEL,fd,&event) < 0)
        record()<< getpid() <<": epoll_del error" ;
    m_channels[fd].reset();
    m_https[fd].reset();
}
vector<shared_ptr<Channel>> Epoll::geteventsreq(int event_num)
{
    vector<ptr_channel> req_data;
    for(int i=0;i<event_num;++i)
    {
        int fd = m_events[i].data.fd;
        ptr_channel tmp = m_channels[fd];
        if(tmp)
        {
            tmp->setRevents(m_events[i].events);
            tmp->setEvents(0);
            req_data.push_back(tmp);
        }else
        {
            record()<< "shared_ptr<Channel> is invalid" ;
        }
    }
    return req_data;
}
vector<shared_ptr<Channel>> Epoll::poll()
{
    //m_events.clear();
    int event_cnt = 
            epoll_wait(m_epollfd,&(*m_events.begin()),m_events.size(),EPOLLWAIT_TIME);
    vector<shared_ptr<Channel>> req_data= geteventsreq(event_cnt);
    return req_data;
}

int Epoll::getepollfd()
{
    return m_epollfd;
}
void Epoll::handleexpired()
{
    m_tq.handler_expired_event();
}